#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
#include "lexical.h"
#include "statemachine.h"


void preloadSymboltable()
{
				/* Token definitions for keywords:
				 * 
				 * fixed2	100
				 * void		101
				 * int			102
				 * ;			103
				 * {			104
				 * }			105
				 * (			106
				 * )			107				 
				 * +			108
				 * -			109
				 * "*"			110
				 *"/"			111
				 * %			112
				 * &&			113
				 * ||			114
				 * !=			115
				 * ==		116
				 * =			117
				 * <=		118
				 * >=		119
				 * >			120
				 * <			121
				 * .			122
				 * ,			123
				 * if			124
				 * else		125
				 * while		126
				 * input 		127
				 * output	128
				 */
				
				symbol symbolEntry;
				symbolEntry.lexture[0]  = 'Q';
				symbolEntry.lexture[1] = 0;
				//symbolEntry.lexture[1]  = 'i';
				//symbolEntry.lexture[2]  = 'x';
				//symbolEntry.lexture[3]  = 'e';
				//symbolEntry.lexture[4]  = 'd';
				//symbolEntry.lexture[5]  = '2';
				//symbolEntry.lexture[6]  = 0;
				symbolEntry.token[0] = 100;
				symbolEntry.value = 0;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = 'v';
				symbolEntry.lexture[1] = 'o';
				symbolEntry.lexture[2] = 'i';
				symbolEntry.lexture[3] = 'd';
				symbolEntry.lexture[4] = 0;
				symbolEntry.token[0] = 101;
				symboltable.push_back(symbolEntry);
			
				symbolEntry.lexture[0] = 'i';
				symbolEntry.lexture[1] = 'n';
				symbolEntry.lexture[2] = 't';
				symbolEntry.lexture[3] = 0;
				symbolEntry.token[0] = 102;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = ';';
				symbolEntry.lexture[1] = 0;
				symbolEntry.token[0] = 103;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '{';
				symbolEntry.token[0] = 104;
				symboltable.push_back(symbolEntry);				
				
				symbolEntry.lexture[0] = '}';
				symbolEntry.token[0] = 105;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '(';
				symbolEntry.token[0] = 106;
				symboltable.push_back(symbolEntry);				
				
				symbolEntry.lexture[0] = ')';
				symbolEntry.token[0] = 107;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '+';
				symbolEntry.token[0] = 108;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '-';
				symbolEntry.token[0] = 109;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '*';
				symbolEntry.token[0] = 110;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '/';
				symbolEntry.token[0] = 111;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '%';
				symbolEntry.token[0] = 112;
				symboltable.push_back(symbolEntry);			
				
				symbolEntry.lexture[0] = '&';
				symbolEntry.lexture[1] = '&';
				symbolEntry.lexture[2] = 0;
				symbolEntry.token[0] = 113;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '|';
				symbolEntry.lexture[1] = '|';
				symbolEntry.token[0] = 114;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '!';
				symbolEntry.lexture[1] = '=';
				symbolEntry.token[0] = 115;
				symboltable.push_back(symbolEntry);		
				
				symbolEntry.lexture[0] = '=';
				symbolEntry.lexture[1] = '=';
				symbolEntry.token[0] = 116;
				symboltable.push_back(symbolEntry);		
				
				symbolEntry.lexture[0] = '=';
				symbolEntry.lexture[1] = 0;
				symbolEntry.token[0] = 117;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '<';
				symbolEntry.lexture[1] = '=';
				symbolEntry.token[0] = 118;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '>';
				symbolEntry.lexture[1] = '=';
				symbolEntry.token[0] = 119;
				symboltable.push_back(symbolEntry);
				
				
				symbolEntry.lexture[0] = '>';
				symbolEntry.lexture[1] = 0;
				symbolEntry.token[0] = 120;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = '<';
				symbolEntry.token[0] = 121;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = 'r';
				symbolEntry.lexture[1] = 'e';
				symbolEntry.lexture[2] = 't';
				symbolEntry.lexture[3] = 'u';
				symbolEntry.lexture[4] = 'r';
				symbolEntry.lexture[5] = 'n';
				symbolEntry.lexture[6] = 0;
				symbolEntry.token[0] = 122;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = ',';
				symbolEntry.lexture[1] = 0;
				symbolEntry.token[0] = 123;
				symboltable.push_back(symbolEntry);

				symbolEntry.lexture[0] = 'i';
				symbolEntry.lexture[1] = 'f';
				symbolEntry.lexture[2] = 0;
				symbolEntry.token[0] = 124;
				symboltable.push_back(symbolEntry);
				
				symbolEntry.lexture[0] = 'e';
				symbolEntry.lexture[1] = 'l';
				symbolEntry.lexture[2] = 's';
				symbolEntry.lexture[3] = 'e';
				symbolEntry.lexture[4] = 0;
				symbolEntry.token[0] = 125;
				symboltable.push_back(symbolEntry);	
				
				symbolEntry.lexture[0] = 'w';
				symbolEntry.lexture[1] = 'h';
				symbolEntry.lexture[2] = 'i';
				symbolEntry.lexture[3] = 'l';
				symbolEntry.lexture[4] = 'e';
				symbolEntry.lexture[5] = 0;
				symbolEntry.token[0] = 126;
				symboltable.push_back(symbolEntry);	
				
				symbolEntry.lexture[0] = 'i';
				symbolEntry.lexture[1] = 'n';
				symbolEntry.lexture[2] = 'p';
				symbolEntry.lexture[3] = 'u';
				symbolEntry.lexture[4] = 't';
				symbolEntry.lexture[5] = 0;
				symbolEntry.token[0] = 127;
				symboltable.push_back(symbolEntry);	
				
				symbolEntry.lexture[0] = 'o';
				symbolEntry.lexture[1] = 'u';
				symbolEntry.lexture[2] = 't';
				symbolEntry.lexture[3] = 'p';
				symbolEntry.lexture[4] = 'u';
				symbolEntry.lexture[5] = 't';
				symbolEntry.lexture[6] = 0;
				symbolEntry.token[0] = 99;
				symboltable.push_back(symbolEntry);				
		
}

void lexicalAnalysis(char* argv[])
{
	 // We assume argv[1] is a filename to open
    ifstream the_file ( argv[1] );
    // Always check to see if file opening succeeded
    if ( !the_file.is_open() )
    	cout<<"Could not open file\n";
    else 
    {
	  preloadSymboltable();
	  char x;
	  unsigned char state;
	  string buffer = "";
	  // the_file.get ( x ) returns false if the end of the file
	  //  is reached or an error occurs
	  state = 1;
	  buffer = "";
	  
	while ( the_file.get ( x ) )
	{        
		if (statetable[state][BU] == 'y')
		// spol char pointer 1 tilbage
		{
			the_file.seekg(-1, ios::cur);
			buffer.erase(buffer.end()-1);
		}
	
		if (statetable[state][accept] == 'y')
		{
			int lextureInSymboltable = -1;
			// search if token exists in symboltable
			vector<symbol>::iterator it;
			int i = 0;
			//buffer.erase(buffer.end()-1);
			for (it=symboltable.begin(); it<symboltable.end(); it++)
			{
				if (strcmp(symboltable[i].lexture, buffer.data()) == 0)
				{
					lextureInSymboltable = i;
				}
				i++;
			}
			// ny post i sym tabel af typen state
	
			if (lextureInSymboltable == -1) // Tjekker om symbol IKKE findes i tabellen
			{
				/*	if(symboltable.size() == symboltable.max_size())
				{
					symboltable.resize(2*symboltable.max_size());	
				}*/
				symbol symbolEntry;
				memcpy(symbolEntry.lexture, buffer.c_str(), buffer.length()+1);
				symbolEntry.token[0] = state;
				symbolEntry.value = atoi(buffer.c_str());
				symboltable.push_back(symbolEntry);
				buffer = "";
				// Add corresponding entry in symbol table to lexeme array
			//	lexemeFile << (symboltable.size()-1) << endl;
				lexemeArray.push_back(symboltable.size()-1);
			}
			else 
			{
				//Add corresponding entry in symbol table to lexeme array
				//	lexemeFile.write((char)lextureInSymboltable);
				//lexemeFile << lextureInSymboltable << endl;
					lexemeArray.push_back(lextureInSymboltable);
				buffer="";
			}
		}
	
		buffer.append(1,x);
	
		if (('0' <= x) && (x <= '9')) // is digit
		{	
			state = statetable[state][digit];
		}
	  	else if ( ('a' <= (x | 0x20)) && ((x | 0x20) <= 'z')) //is letter
	  	{
			state = statetable[state][letter];				
		}
		else switch (x) {
			case '_':
					state = statetable[state][underscore];
					break;
			case '{':
					state = statetable[state][tuborg_B];
					break;   
			case '}':
					state = statetable[state][tuborg_E];
					break;
			case '(':
					state = statetable[state][paranthesis_B];
					break;
			case ')':
					state = statetable[state][paranthesis_E];
					break;
			case '+':
					state = statetable[state][_plus];
					break;
			case '-':
					state = statetable[state][_minus];
					break;
			case '*':
					state = statetable[state][_multiply];
					break;
			case '/':
					state = statetable[state][front_slash];
					break;
			case '%':
					state = statetable[state][modulo];
					break;
			case '&':
					state = statetable[state][single_and];
					break;
			case '|':
					state = statetable[state][pipe];
					break;
			case '!':
					state = statetable[state][exclamation];
					break;
			case '<':
					state = statetable[state][less_than];
					break;
			case '>':
					state = statetable[state][greater_than];
					break;
			case '=':
					state = statetable[state][equals];
					break;
			case '.':
					state = statetable[state][dot];
					break;
			case ';':
					state = statetable[state][semicolon];
					break;
			case ',':
					state = statetable[state][comma];
					break;
			case '\r':
					state = statetable[state][whitespace];
					break;
			case '\n':
					state = statetable[state][whitespace];
					break;
			case ' ':
					state = statetable[state][whitespace];
					break;
			case '\t':
					state = statetable[state][whitespace];
					break;
			default:
					state = statetable[state][AE];
			}
	
		if (state==1 || state==30)
		{
			//buffer.erase(buffer.end()-1);
			the_file.seekg(-1, ios::cur);
			buffer = "";
	  	}
	   	else if (state==29)
	  	{
	  		//		the_file.seekg(-1, ios::cur);
			buffer = "";
		}
		else if (state == 28)
		{
			printf("Error state");
		}
	}				
	// Put $ in symboltable and lexemearray
	symbol symbolEntry;
	symbolEntry.token[0] = 98;
	symboltable.push_back(symbolEntry);
	lexemeArray.push_back(symboltable.size()-1);
	
	cout << "Lexeme Array:" << endl;
	for (int i=0; i<(int)lexemeArray.size(); i++)
		cout << lexemeArray[i] << " ";
	
	cout << endl << endl << "Symbol table:" << endl;
	cout << "\"Lexture\"" << "," << "\"Token\"" << "," << "\"Value\"" << endl;
	for (int i=0; i<(int)symboltable.size(); i++)
	{
		cout << "\"" << symboltable[i].lexture << "\"" << "," << "\"" << (int)symboltable[i].token[0] << "\"" << "," << symboltable[i].value << endl;	
	}	
	
	cout << endl << endl << "Reconstructed code:" << endl;
	for (int i=0; i<(int)lexemeArray.size(); i++)
		cout << symboltable[lexemeArray[i]].lexture << " ";
	cout << "\n";
}
    }